<?php
namespace tool;
use support\think\Cache;
use support\Log;
class Wxin
{
    protected $appId;
    protected $appSecret;
    protected $token;
    protected $cachePrefix = 'wechat_';

    public function __construct()
    {
        // 从配置文件中获取微信配置（建议放在 config/wechat.php）
        $this->appId = config('wx.gzh_appid', '');
        $this->appSecret = config('wx.gzh_secret', '');
        $this->token = config('wx.gzh_token', '');
    }

    /**
     * 验证微信服务器Token
     */
    public function verifyToken(array $query): bool
    {
        $signature = $query['signature'] ?? '';
        $timestamp = $query['timestamp'] ?? '';
        $nonce = $query['nonce'] ?? '';
        $echostr = $query['echostr'] ?? '';
        // 参数校验
        if (empty($signature) || empty($timestamp) || empty($nonce)) {
            return false;
        }

        // 生成签名
        $tmpArr = [$this->token, $timestamp, $nonce];
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $sign = sha1($tmpStr);

        // 返回验证结果
        return $sign === $signature;
    }

    /**
     * 获取AccessToken（带缓存）
     */
    public function getAccessToken(): string
    {
        $cacheKey = $this->cachePrefix . 'access_token';
        $one=Cache::get($cacheKey);
        if(!$one){
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential". "&appid={$this->appId}&secret={$this->appSecret}";
            $response = $this->httpGet($url);
            $data = json_decode($response, true);
            if (empty($data['access_token'])) {
                Log::error('获取AccessToken失败', $data);
                throw new \Exception('获取AccessToken失败');
            }
            // 提前200秒过期（微信默认7200秒）
            Cache::set($cacheKey, $data['access_token'], $data['expires_in'] - 200);
            $one=$data['access_token'];
        }
        return $one;
    }

    /**
     * 获取JSAPI Ticket（带缓存）
     */
    public function getJsApiTicket(): string
    {
        $cacheKey = $this->cachePrefix . 'jsapi_ticket';
        $one=Cache::get($cacheKey);
        if(!$one){
            $accessToken = $this->getAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token={$accessToken}";
            $response = $this->httpGet($url);
            $data = json_decode($response, true);
            if (empty($data['ticket'])) {
                Log::error('获取ticket失败', $data);
                throw new \Exception('获取ticket失败');
            }
            // 提前200秒过期（微信默认7200秒）
            Cache::set($cacheKey, $data['ticket'], $data['expires_in'] - 200);
            $one=$data['ticket'];
        }
        return $one;
    }

    /**
     * 生成JS-SDK签名包
     */
    public function getSignPackage(string $url): array
    {
        $yuming=request()->host(true);
       if($yuming =='127.0.0.1'){
           $ticket = '';
       }else{
           $ticket = $this->getJsApiTicket();
       }

        $timestamp = time();
        $nonceStr = $this->createNonceStr();

        // 生成签名
        $string = "jsapi_ticket={$ticket}&noncestr={$nonceStr}&timestamp={$timestamp}&url={$url}";
        $signature = sha1($string);

        return [
            'appId'     => $this->appId,
            'nonceStr'  => $nonceStr,
            'timestamp' => $timestamp,
            'url'       => $url,
            'signature' => $signature,
            'rawString' => $string // 调试用，正式环境建议移除
        ];
    }

    /**
     * 生成随机字符串
     */
    protected function createNonceStr(int $length = 16): string
    {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }

    /**
     * HTTP GET请求
     */
    protected function httpGet(string $url): string
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $response = curl_exec($ch);
        curl_close($ch);
        return $response;
    }
}